/* UniApo: Map Editor
 * File:   main.cpp
 * Author: Jeffrey Geyssens
 *
 * Created on May 13, 2010, 5:19 PM
 *
 * An interface for creating and editing MAP Files.
 * After selecting DRT match option, the MAPfile is serialized.
 *
 */

//TODO: Allow SCB editing from this interface
//TODO: Check when adding DRT in bulk if DRT exists
//Preferably by loading SCBEditor but if you use copy paste thats fine too

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include "../UniApoLib/MAPFile.h"

using namespace std;

int main(int argc, char **argv) {
    if (argc >> 3) {
        cerr << "ERROR (MAP File Editor): Requires at least two arguments";
        cerr << endl;
        return 1;
    }
    void processLine(string const & lineData);
    string option = argv[1];
    string file = argv[2];
    string filename = file.substr(0, file.size() - 4);
    string extension = file.substr(file.size() - 4, file.size());

    //First we check if a correct filename was supplied
    if (extension != ".MAP") {
        cerr << "ERROR in extension (MAP File Editor):";
        cerr << " Expected filename.SCB extension" << endl;
        return 3;
    }
    //Next we check if the option format supplied is correct
    //If the size of the argument (which must be 2) is incorrect
    //or the argument does not start with '-'
    if ((option.size() != 2) || (option.at(0) != '-')) {
        cerr << "ERROR in 1st argument (MAP File Editor): Use -n for new file,";
        cerr << " -o for open existing file or -d to delete a file." << endl;
        return 2;
    }

    char coption = option.at(1); //operation argument
    //Creating empty MAP object and MAPFile path for later
    MAPFile MAP;
    MAP.name(filename);

    switch (coption) {
        case 'n':
            //When a new map is created, the user submits the new MAP name
            //and the .SCB and .DBS file.

        {
            if (argc != 5) {
                cerr << "ERROR (MAP File Editor): Requires four arguments";
                cerr << endl;
                return 1;
            }
            string SCBfile = argv[3];

            string SCBfilename = SCBfile.substr(0, SCBfile.size() - 4);
            string SCBextension
                    = SCBfile.substr(SCBfile.size() - 4, SCBfile.size());

            //First we check if a correct filename was supplied
            if (SCBextension != ".SCB") {
                cerr << "ERROR in extension (MAP File Editor):";
                cerr << " Expected filename.SCB extension" << endl;
                return 3;
            }

            string DBSfile = argv[4];
            string DBSfilename = DBSfile.substr(0, DBSfile.size() - 4);
            string DBSextension
                    = DBSfile.substr(DBSfile.size() - 4, DBSfile.size());

            //First we check if a correct filename was supplied
            if (DBSextension != ".DBS") {
                cerr << "ERROR in extension (MAP File Editor): ";
                cerr << "Expected filename.SCB extension" << endl;
                return 3;
            }

            //takes a SCB and DBS file as input and creates map skeleton

            MAP.autogenerate(SCBfilename, DBSfilename);
            //Creation of a new file
            //Store in UniApo/Saves/MAP
            cout << "Generating MAP: " << filename << endl;
            MAP.name(filename);
            //cout << MAP.getPath() << endl;

            //This saves the file in MAP

            MAP.buildFile();
            cout << "New MAP file created" << endl;

        }
            break;

        case 'o':
        {
            if (argc != 3) {
                cerr << "ERROR (MAP File Editor): Requires 2 arguments" << endl;
                return 1;
            }

            cout << "Open Existing File" << endl;
            MAP.loadFile();
            cout << "Select Section" << endl;
        }
            break;
        case 'd':
        {
            //are you sure?
            string confirm;
            while ((confirm != "y") || (confirm != "n")) {
                cout << "Are you sure?(y/n): " << endl;
                getline(cin, confirm);
                if (confirm == "n") {
                    return 0;
                }
                if (confirm == "y") {
                    if (remove(MAP.getPath().c_str()) != 0) {
                        cerr << "ERROR (SCB File Editor): No such file" << endl;
                        return 4;
                    } else
                        cout << "File deleted" << endl;
                    break;
                }
            }
        }
            break;
        default:
        {
            cerr << "ERROR (MAP File Editor): " << endl;
            cerr << "1st argument must be -n for new file";
            cerr << "-o for open existing file or -d to delete a file" << endl;
            return 2;
        }
            break;
    }
    string imod;
    while (imod != "q") {
        //MAP.print();

        cout << "Enter command (a,d,r,p,m,q,s or h for help): ";
        getline(cin, imod);
        if (imod == "h") {
            cout << "---MAPEditor Help---" << endl;
            cout << "Type a to add Storage Rules" << endl;
            cout << "Type d for DRT editing" << endl;
            cout << "(Updates both SCB file and MAP file)" << endl;
            cout << "Type r for RT editing" << endl;
            cout << "Type p to add and delete Production Rules" << endl;
            cout << "(To and From source SCB)" << endl;
            cout << "Type m to populate database" << endl;
            cout << "Type s to save and q to quit" << endl;
        }
        if (imod == "s") {
            cout << "saving" << endl;
            MAP.buildFile();

            cout << "file saved" << endl;
        }

        if (imod == "m") {
            cout << "Creating Local Database..." << endl;
            MAP.createDB();
            cout << "file saved" << endl;
        }
        //Yes it's copied from SCB editor
        //But it does the trick
        //Edit Production rule container

        if (imod == "p") {
            string pmod, NT, derivation;
            SCBFile& openSCB = MAP.getSCB();
            cout << "Production Rule Editor" << endl;
            while (pmod != "q") {
                //clear screen?
                openSCB.printPRule();

                cout << "Enter Command (a,b,d,q,s or h for help): ";
                getline(cin, pmod);
                if (pmod == "a") {
                    cout << "Enter Generating Non Terminal: ";
                    getline(cin, NT);
                    cout << "Enter Generated Derivation: ";
                    getline(cin, derivation);

                    if ((NT == "") || (derivation == "")) {
                        cerr << "Non Terminal or Derivation can not be left blank" << endl;
                    }
                    openSCB.addPRule(NT, derivation);

                }
                if (pmod == "b") {
                    cout << "Adding PR entries in bulk" << endl;
                    cout << "Enter full path of csv file: ";
                    string path;
                    getline(cin, path);
                    openSCB.bulkPRule(path);
                    openSCB.printPRule();
                }

                if (pmod == "d") {
                    cout << "Enter Non Terminal to delete: ";
                    getline(cin, NT);
                    openSCB.printPRule(NT);

                    if (openSCB.count(NT) == 1) {
                        openSCB.removePRule(NT, 1);
                    } else {

                        cout << "Which production do you want to delete: ";
                        int entryNo;
                        string xline;
                        getline(cin, xline);
                        stringstream ss(xline);
                        ss >> entryNo;
                        openSCB.removePRule(NT, entryNo);
                    }
                }
                if (pmod == "s") {
                    cout << "saving: " << openSCB.getPath() << endl;
                    openSCB.buildFile();
                    cout << "file saved" << endl;
                }

                if (pmod == "h") {
                    cout << "**********Production Rule (PR) Editor Help************* " << endl;
                    cout << "In this section we store an list of production rules, sorted by generating Non Terminal" << endl;
                    cout << "You can add and delete PR to the list using this module" << endl;
                    cout << "PR entries are of type: NT    ::==    DerivationString" << endl;


                }
            }
        }

        if (imod == "a") {
            string amod;
            cout << "Storage Rule Container Editor" << endl;
            cout << "*****************************" << endl;
            while (amod != "q") {
                cout << "Enter Command (n,e,d,q,s or h for help): ";
                getline(cin, amod);
                if (amod == "h") {
                    cout << "MAP Editor (Storage Rule Editor Editor) Help";
                    cout << endl;
                    cout << "*****************************************" << endl;
                    cout << "Storage Rules specify how parsed";
                    cout << " data strings are stored in the database." << endl;
                    cout << "Such an element contains 2 parts: " << endl;
                    cout << "1) Sentence Structure:" << endl;
                    cout << "The stucture of the sentence represented in";
                    cout << " Terminals. " << endl;
                    cout << "example: (D:Person)(L:\" \")(D:Relationship)";
                    cout << "(L:\" \")(D:Person) might represent";
                    cout << " the string \"Jeffrey likes Hayat\"." << endl;
                    cout << "please note: the spaces denoted by ";
                    cout << "Literal Terminals. " << endl;
                    cout << "2) Parameterized SQL statements:" << endl;
                    cout << "DML SQL statements of which the values to be";
                    cout << " inserted are parameterized." << endl;
                    cout << "This convention can be understood";
                    cout << " by the following example:" << endl;
                    cout << "To store data derived from \"Jeffrey likes Hayat\"";
                    cout << " in database table tblx the following ";
                    cout << "SQL statement is used: " << endl;
                    cout << "INSERT INTO \"tblx\" (\"actor\",\"relationship\"";
                    cout << ",\"receiver\")";
                    cout << "VALUES(\"Jeffrey\",\"likes\",\"Hayat\")" << endl;
                    cout << "Converted in parameterized format we get:" << endl;
                    cout << "INSERT INTO \"tblx\" (\"actor\",\"relationship\"";
                    cout << ",\"receiver\")";
                    cout << "VALUES(\"(D:Person[1])\",";
                    cout << "\"(D:Relationship[1])\",\"(D:Person[2])\")" << endl;

                    cout << "Type n to create a new Storage Rule" << endl;
                    cout << "Type e to edit an existin Storage Rule";
                    cout << " (more help in editing mode)" << endl;
                    cout << "Type d to delete a SRULEure" << endl;

                }
                if (amod == "s") {
                    cout << "saving" << endl;
                    MAP.buildFile();
                    cout << "file saved" << endl;
                }

                if (amod == "n") {

                    string newst;
                    cout << "Enter Sentence Structure: ";

                    getline(cin, newst);
                    if (newst != "#") {
                        MAP.addStructure(newst);
                    }
                }

                if (amod == "e") {

                    MAP.printSRULE();
                    int entryNo;
                    string xline;
                    cout << "Submit SRULE number to edit: ";
                    getline(cin, xline);
                    if (xline != "#") {
                        stringstream ss(xline);
                        ss >> entryNo;
                        string n;

                        n = MAP.getSRULEid(entryNo);
                        MAP.printSRULE(n);
                        string aemod;
                        while (aemod != "q") {
                            cout << "Enter Command (a,d,b,q,s or h for help): ";
                            getline(cin, aemod);
                            if (aemod == "h") {
                                cout << "MAP EDITOR - ADD PSQL STATEMENT" << endl;
                            }
                            if (aemod == "s") {
                                cout << "saving" << endl;
                                MAP.buildFile();
                                cout << "file saved" << endl;
                            }
                            if (aemod == "a") {
                                string psql;
                                cout << "Submit Parameterized SQL Statement: ";
                                cout << endl;
                                getline(cin, psql);
                                MAP.addPSQL(n, psql);
                            }

                        }

                    }
                }

            }
        }

        if (imod == "r") {
            string rmod;
            cout << "Reference Terminal Editor" << endl;
            cout << "******************************" << endl;
            while (rmod != "q") {
                cout << "Enter Command (b,n,e,d,q,s or h for help): ";
                getline(cin, rmod);
                if (rmod == "h") {
                    cout << "MAP Editor (RT editing) Help" << endl;
                    cout << "****************" << endl;
                    cout << "Type n to create a new RT" << endl;
                    cout << "Type b to add RTs in bulk" << endl;
                    cout << "Type e to edit an existing RT" << endl;
                    cout << "Type d to delete a RT" << endl;
                    cout << "Example: First create RT (R:Comment)" << endl;
                    cout << "Then edit (R:Comment)" << endl;
                    cout << "You can now specify the following:" << endl;
                    cout << "option t: Specify storage table in database ";
                    cout << "in which elements are stored" << endl;
                    cout << "option a: Specify the storage table attribute";
                    cout << endl;
                }
                if (rmod == "s") {
                    string path;

                    cout << "Saving changes to MAP file..." << endl;
                    MAP.buildFile();

                }
                if (rmod == "n") {
                    string newRT;
                    cout << "Enter New Reference Terminal Name: ";
                    getline(cin, newRT);
                    int nx;
                    nx = newRT.find("(R:");
                    //force parentheses and prefixed by R:
                    if ((nx != 0) || (newRT.at(newRT.size() - 1) != ')')) {
                        //if no parentheses present add them
                        //TODO: stringstream DRT section below
                        stringstream x;
                        x << "(R:" << newRT << ")";
                        newRT = x.str();
                    }
                    MAP.addRT(newRT);
                }

                if (rmod == "b") {
                    string path;

                    cout << "Adding RT data in bulk" << endl;
                    cout << "Enter full path of csv file: ";
                    getline(cin, path);
                    MAP.bulkRT(path);

                }


                //Edit a RT
                if (rmod == "e") {
                    cout << "Editing RT:" << endl;
                    MAP.printRT();
                    int entryNo;
                    string xline;
                    cout << "Enter RT number: ";
                    getline(cin, xline);
                    stringstream ss(xline);
                    ss >> entryNo;

                    //Enter Editing mode
                    string remod;
                    MAP.printRT(entryNo);
                    while (remod != "q") {
                        cout << "enter command (t,a,s,q or h for help): ";
                        cout << endl;
                        getline(cin, remod);
                        if (remod == "h") {
                            cout << "Map Editor - Edit RT help" << endl;
                            cout << "t: Set RT storage table from db" << endl;
                            cout << "a: Set table attribute" << endl;

                        }

                        if (remod == "t") {
                            string currRT, table;
                            currRT = MAP.getRTid(entryNo);
                            cout << "Enter new Table name" << endl;
                            getline(cin, table);
                            cout << currRT << "::" << table;
                            MAP.setRTTable(currRT, table);
                            MAP.printRT(entryNo);

                        }

                        if (remod == "a") {
                            string currRT, s;
                            currRT = MAP.getRTid(entryNo);
                            cout << "Enter new Attribute name" << endl;
                            getline(cin, s);
                            MAP.setRTAttrib(currRT, s);
                            MAP.printRT(entryNo);
                        }

                        if (remod == "s") {
                            cout << "saving" << endl;
                            MAP.buildFile();
                            cout << "file saved" << endl;
                        }
                    }

                }

            }
        }

        //Edit DRT Section
        if (imod == "d") {
            string dmod;
            cout << "Data Reference Terminal editor" << endl;
            cout << "******************************" << endl;
            MAP.printDRT();
            while (dmod != "q") {
                cout << "Enter Command (b,n,e,d,q,s or h for help): ";
                getline(cin, dmod);
                if (dmod == "h") {
                    cout << "MAP Editor (DRT editing) Help" << endl;
                    cout << "****************" << endl;
                    cout << "Type n to create a new DRT" << endl;
                    cout << "Type e to edit an existing DRT" << endl;
                    cout << "Type d to delete a DRT" << endl;
                    cout << "Example: First create DRT (D:Person)" << endl;
                    cout << "Then edit (D:Person)" << endl;
                    cout << "You can now specify the following:" << endl;
                    cout << "option t: Specify the table in database ";
                    cout << "in which elements are stored" << endl;
                    cout << "option d: Specify the field to store" << endl;
                }
                if (dmod == "s") {
                    cout << "Saving changes to MAP file..." << endl;
                    MAP.buildFile();

                }
                if (dmod == "n") {

                    string newdrt;
                    cout << "Enter New Data Reference Terminal Name: ";
                    getline(cin, newdrt);
                    int nx;
                    nx = newdrt.find("(D:");
                    //force parentheses and prefixed by D:
                    if ((nx != 0) || (newdrt.at(newdrt.size() - 1) != ')')) {
                        //if no parentheses present add
                        string x;
                        x = "(D:";
                        x.append(newdrt);
                        x.append(")");
                        newdrt = x;
                    }
                    MAP.addDRT(newdrt);
                    MAP.printDRT();
                }

                if (dmod == "e") {
                    MAP.printDRT();
                    int entryNo;
                    string xline;
                    cout << "Enter DRT number: ";
                    getline(cin, xline);
                    stringstream ss(xline);
                    ss >> entryNo;
                    MAP.printDRT(entryNo); // change to

                    string demod;

                    while (demod != "q") {
                        SCBFile SCB;
                        SCB = MAP.getSCB();
                        cout << "enter command";
                        cout << "(r,a,b,e,t,p,x,d,s,q or h for help):";
                        cout << endl;
                        getline(cin, demod);
                        if (demod == "h") {
                            cout << "Map Editor - Edit DRT help" << endl;
                            cout << "Type r to rename DRT" << endl;
                            cout << "(Saves in MAP and SCB file)" << endl;
                            cout << "Type a to add Symbol Definitions to DRT";
                            cout << endl;
                            cout << "(Saves in MAP and SCB file)" << endl;
                            cout << "Type e to edit Symbol Definitions" << endl;
                            cout << "(Saves in MAP and SCB file)" << endl;
                            cout << "Type b to DRT data in bulk" << endl;
                            cout << "(Saves in MAP and SCB file)" << endl;
                            cout << "Type t to edit database table reference";
                            cout << endl;
                            cout << "(Saves in MAP and SCB file)" << endl;
                            cout << "Type x to edit database Symbol attribute " << endl;
                            cout << "(Saves in MAP and SCB file)" << endl;
                            cout << "Type d to edit Symbol Definitions" << endl;
                            cout << "(Saves in MAP and SCB file)" << endl;

                        }
                        if (demod == "r") {
                            string from, to;
                            from = MAP.getDRTid(entryNo);
                            cout << "Enter new DRT name: " << endl;
                            getline(cin, to);
                            SCB.changeDRT(from, to);
                            //TODO: Change in MAP file to


                        }

                        if (demod == "a") {

                        }


                        if (demod == "t") {
                            string currDRT;
                            string table;
                            currDRT = MAP.getDRTid(entryNo);
                            cout << "Enter new Table name" << endl;
                            getline(cin, table);
                            MAP.setDRTTable(currDRT, table);
                            MAP.printDRT(entryNo);
                        }

                        if (demod == "x") {
                            string currDRT;
                            string s;
                            currDRT = MAP.getDRTid(entryNo);
                            cout << "Enter new Symbol Attribute" << endl;
                            getline(cin, s);
                            MAP.setDRTSymRef(currDRT, s);
                            MAP.printDRT(entryNo);
                        }

                        if (demod == "d") {
                            string currDRT;
                            string d;
                            currDRT = MAP.getDRTid(entryNo);
                            cout << "Enter new Definition Attribute" << endl;
                            getline(cin, d);
                            MAP.setDRTDefRef(currDRT, d);
                            MAP.printDRT(entryNo);
                        }

                        if (demod == "s") {
                            cout << "saving" << endl;
                            //TO SAVE IN SCB FILE
                            cout << SCB.getPath() << endl;
                            SCB.buildFile();
                            MAP.buildFile();
                            cout << "file saved" << endl;
                        }
                        if (demod == "b") {
                            string path;

                            cout << "Adding DRT data in bulk" << endl;
                            cout << "Enter full path of csv file: ";
                            getline(cin, path);
                            MAP.bulkDRT(path);
                        }
                    }


                }

                if (dmod == "b") {
                    string path;

                    cout << "Adding DRT data in bulk" << endl;
                    cout << "Enter full path of csv file: ";
                    getline(cin, path);
                    MAP.bulkDRT(path);
                }

            }
        }

    }
    return 0;
}



